package com.maidada.codesharebackend.util;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;

/**
 * IP地址工具类
 *
 * @author wulinxuan
 */
@Slf4j
public class IpUtil {

    /**
     * 未知IP标识
     */
    private static final String UNKNOWN = "unknown";

    /**
     * 本地IP
     */
    private static final String LOCALHOST_IPV4 = "127.0.0.1";
    private static final String LOCALHOST_IPV6 = "0:0:0:0:0:0:0:1";

    /**
     * IP地址分隔符
     */
    private static final String IP_SEPARATOR = ",";

    /**
     * 获取客户端真实IP地址
     * <p>
     * 通过多个请求头获取IP地址，优先级从高到低：
     * 1. X-Forwarded-For
     * 2. Proxy-Client-IP
     * 3. WL-Proxy-Client-IP
     * 4. HTTP_CLIENT_IP
     * 5. HTTP_X_FORWARDED_FOR
     * 6. X-Real-IP
     * 7. request.getRemoteAddr()
     *
     * @param request HTTP请求对象
     * @return 客户端IP地址
     */
    public static String getIpAddress(HttpServletRequest request) {
        if (request == null) {
            log.warn("获取IP地址失败：request为null");
            return UNKNOWN;
        }

        String ip = null;

        // 1. X-Forwarded-For：Squid 服务代理
        ip = request.getHeader("X-Forwarded-For");
        if (isValidIp(ip)) {
            // 多次反向代理后会有多个IP值，第一个IP才是真实IP
            int index = ip.indexOf(IP_SEPARATOR);
            if (index != -1) {
                ip = ip.substring(0, index);
            }
            return ip.trim();
        }

        // 2. Proxy-Client-IP：apache 服务代理
        ip = request.getHeader("Proxy-Client-IP");
        if (isValidIp(ip)) {
            return ip.trim();
        }

        // 3. WL-Proxy-Client-IP：weblogic 服务代理
        ip = request.getHeader("WL-Proxy-Client-IP");
        if (isValidIp(ip)) {
            return ip.trim();
        }

        // 4. HTTP_CLIENT_IP
        ip = request.getHeader("HTTP_CLIENT_IP");
        if (isValidIp(ip)) {
            return ip.trim();
        }

        // 5. HTTP_X_FORWARDED_FOR
        ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        if (isValidIp(ip)) {
            return ip.trim();
        }

        // 6. X-Real-IP：nginx服务代理
        ip = request.getHeader("X-Real-IP");
        if (isValidIp(ip)) {
            return ip.trim();
        }

        // 7. 获取request的remoteAddr
        ip = request.getRemoteAddr();
        if (StrUtil.isBlank(ip)) {
            log.warn("获取IP地址失败：所有方式都无法获取到IP");
            return UNKNOWN;
        }

        // 处理本地IP
        if (LOCALHOST_IPV6.equals(ip)) {
            ip = LOCALHOST_IPV4;
        }

        return ip.trim();
    }

    /**
     * 验证IP地址是否有效
     *
     * @param ip IP地址
     * @return true-有效，false-无效
     */
    private static boolean isValidIp(String ip) {
        return StrUtil.isNotBlank(ip) && !UNKNOWN.equalsIgnoreCase(ip);
    }

    /**
     * 将IP地址转换为适合作为Redis key的格式
     * 将点号替换为下划线，避免key中出现特殊字符
     *
     * @param ip IP地址
     * @return 格式化后的IP字符串
     */
    public static String formatIpForKey(String ip) {
        if (StrUtil.isBlank(ip)) {
            return UNKNOWN;
        }
        // 将点号和冒号替换为下划线
        return ip.replace(".", "_").replace(":", "_");
    }
}

